<?php

  /**
   * PostsController
   *
   * Класс контроллера для работы с постами
   */

  final class PostsController extends XMLController
  {
    /**
     * выбранный пост
     *
     * @var Post
     */
    private $_post = null;

    /**
     * предопределенные действия
     *
     * @return array
     * @access public
     */
    public function actions()
    {
      $posts = array("class" => "FilterAction", "view" => $this->id);

      return array(
        "news"   => $posts,
        "public" => $posts,
        "blog"   => $posts,
        "post"   => "AjaxAction",
        "add"    => "AjaxAction"
      ) + parent::actions();
    }

    /**
     * Action отобразить запрошенный пост
     *
     * @param mixed $id идентификатор или заголовок поста
     * @return void
     * @access public
     */
    public function actionPost($id)
    {
      if ($id)
      {
        /** @var $post Post */
        $post        = Post::model();
        $this->_post = is_numeric($id) ? $post->findByPk($id) : $post->findByAttributes(array("title" => $id));
      }

      $this->runPreAction(array("data" => array("post" => $this->_post)));
    }

    /**
     * Action добавить пост
     *
     * $_POST == array(
     *   "post" => array(
     *     "type"    => "тип поста(блог, новость, публикация)",
     *     "title"   => "заголовок поста",
     *     "content" => "текст"
     *   ),
     *   "tags"          => идентификаторы или названия тегов(массив)
     *   "illustrations" => имена загруженных файлов(массив)
     *   "mainImage"     => номер основной иллюстрации
     * )
     *
     * @return void
     * @access public
     */
    public function actionAdd()
    {
      $data = $this->getParam("post");
      WebApplication::validate($data["type"]);

      /** @var $app WebApplication */
      $app = $this->app;
      /** @var $user CWebUser */
      $user = $app->user;

      $access = $this->checkAccess("create_$data[type]", false);
      if (!($access || $user->isGuest))
        $data["is_temporary"] = 1;

      WebApplication::validate($access || isset($data["is_temporary"]), 403);

      $post             = new Post();
      $post->attributes = $data;
      WebApplication::validate($post->save(), 500, "Не удалось создать пост");

      $id = $post->id;
      $this->addTags($id);
      $this->addPhotos($id);

      if (isset($data["is_temporary"]))
        WebApplication::response(CHtml::tag("pre", array(), "{$app->request->baseUrl}/user/profile/$user->id"), "text/html");
      else
        $this->runPreAction(array("data" => array("post" => $post)));
    }

    /**
     * Action обновить пост
     *
     * $_POST == array(
     *   "id"   => идентификатор поста,
     *   "post" => array(
     *     "title"   => "заголовок поста",
     *     "content" => "текст"
     *   ),
     *   "tags"          => идентификаторы или названия тегов(массив)
     *   "illustrations" => имена загруженных файлов(массив)
     *   "mainImage"     => номер основной иллюстрации
     * )
     *
     * @return void
     * @access public
     */
    public function actionUpdate()
    {
      /** @var $post Post */
      WebApplication::validate($post = Post::model()->findByPk($id = $this->getParam("pid")));
      $this->checkAccess("edit_$post->type", true, array("post" => $post));

      $post->attributes = $this->getParam("post");
      WebApplication::validate($post->save(), 500, "Не удалось обновить пост");

      $response = array(
        "id"            => $id,
        "title"         => $post->title,
        "content"       => $post->content,
        "tags"          => array(),
        "illustrations" => array(),
        "mainImage"     => 0
      );

      $tags = $this->addTags($id);
      if (!empty($tags))
      {
        Tag::model()->deleteAll("`rec_id`='$id' and not `tag_id` in('".join("','", $tags)."')");
        /** @var $tag TagName */
        foreach (TagName::model()->findAllByPk($tags) as $tag)
          $response["tags"][$tag->id] = $tag->name;
      }

      $photos = $this->addPhotos($id);
      foreach ($post->photos as $photo)
        if (($n = array_search($photo->photo, $photos)) === false)
          $photo->delete();
        else
        {
          $response["illustrations"][$n] = $photo->photo;
          if ($photo->is_main)
            $response["mainImage"] = $n;
        }
      ksort($response["illustrations"], SORT_NUMERIC);
      $response["illustrations"] = array_values($response["illustrations"]);

      WebApplication::response($response);
    }

    /**
     * Action удалить пост
     *
     * $_POST == array("id" => идентификатор поста)
     *
     * @return void
     * @access public
     */
    public function actionRemove()
    {
      WebApplication::validate($id = $this->getParam("id"));
      /** @var $post Post */
      WebApplication::validate($post = Post::model()->findByPk($id), 500, "Пост не найден");

      $this->checkAccess("remove_$post->type", true, array("post" => $post));

      WebApplication::response(array(
        "show" => $post->sentencedInvert(),
        "href" => $this->createUrl($post->type)
      ));
    }

    /**
     * подготовительные действия
     *
     * @param CAction $action
     * @return bool
     */
    protected function beforeAction($action)
    {
      if (in_array($action->id, array("news", "public", "blog", "post")))
      {
        Post::model()->sentence();
        Comment::model()->sentence();
      }

      return parent::beforeAction($action);
    }

    /**
     * заголовок страницы для указанного метода
     *
     * @param string $action имя метода
     * @return string
     * @access public
     */
    public function getActionTitle($action)
    {
      return $this->_post ? $this->_post->title : parent::getActionTitle($action);
    }

    /**
     * добавить теги к посту
     *
     * $_POST == array("tags" => идентификаторы или названия тегов(массив))
     *
     * @param int $pid идентификатор поста
     * @return int[] идентификаторы тегов
     * @access private
     */
    private function addTags($pid)
    {
      $atags = $this->getParam("tags");

      if (is_array($atags))
      {
        /** @var $names TagName */
        $names = TagName::model();
        /** @var $tags Tag */
        $tags = Tag::model();

        foreach ($atags as &$tag)
        {
          if (!($runValidator = is_numeric($tag)))
            if ($tag = trim(preg_replace("/[^\w\s,А-Яа-яёЁ]/ui", "", preg_replace("/[\s_]+/", " ", $tag))))
              foreach (explode(",", $tag) as $name)
              {
                $attrs = array("name" => trim($name), "type" => TagName::TAG);
                /** @var $row TagName */
                $row = $names->findByAttributes($attrs);
                $tag = $row ? $row->id : $names->createRecord($attrs);
              }

          if ($tag)
            try
            {
              $tags->createRecord(array("tag_id" => $tag, "rec_id" => $pid), $runValidator);
            }
            catch (CDbException $e)
            {
            }
        }

        return $atags;
      }

      return array();
    }

    /**
     * добавить иллюстрации к посту
     *
     * $_POST == array(
     *   "illustrations" => имена загруженных файлов(массив)
     *   "mainImage"     => номер основной иллюстрации
     * )
     *
     * @param int $pid идентификатор поста
     * @return string[]
     * @access private
     */
    private function addPhotos($pid)
    {
      $illustrations = $this->getParam("illustrations");

      if (is_array($illustrations))
      {
        /** @var $photos Photo */
        $photos  = Photo::model();
        $mainNum = min(max($this->getParam("mainImage"), 0), count($illustrations) - 1);
        $n       = 0;
        foreach ($illustrations as &$photo)
        {
          $pk    = array("photo" => $photo = basename($photo), "post_id" => $pid);
          $attrs = array("order" => $n, "is_main" => $n++ == $mainNum ? 1 : null);
          if ($rec = $photos->findByPk($pk))
            $rec->saveAttributes($attrs);
          else
            if (!$photos->createRecord($pk + $attrs))
              --$n;
        }
        return $illustrations;
      }

      return array();
    }
  }

?>
